package cn.wenhaha.app.log;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Entity;
import cn.hutool.json.JSONUtil;
import cn.wenhaha.app.log.bean.LogRow;
import cn.wenhaha.common.bean.entity.Switch;
import cn.wenhaha.common.bean.entity.TimeEntity;
import cn.wenhaha.common.config.GlobalApp;
import cn.wenhaha.common.db.bean.SysSyncError;
import cn.wenhaha.common.db.bean.SysSyncReport;
import cn.wenhaha.job.Job;
import cn.wenhaha.job.WynJobBean;
import cn.wenhaha.sync.core.SyncErrorReport;
import cn.wenhaha.sync.core.SyncReport;
import cn.wenhaha.sync.core.SyncSuccessReport;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;

/**
 * 同步数据统计 30秒跑一次
 * --------
 *
 * @author ：wyndem
 * @Date ：Created in 2022-12-17 17:39
 */
@Job(corn = "0/30 * * * * ? ", jobId = 2L)
public class SyncLogReportHandler extends WynJobBean {

    private static final Lock lock = new ReentrantLock();

    private static List<LogRow> waitList = new ArrayList<>();

    private final Logger logger = LoggerFactory.getLogger(SyncLogReportHandler.class);

    @Resource
    private SysSyncReport syncReport;
    @Resource
    private SysSyncError syncError;


    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        logger.debug("开始记录同步报表");
        List<LogRow> logRowList = waitList;
        if (CollUtil.isEmpty(logRowList) || !GlobalApp.isLoadConfigDb()) return;
        resetList();
        // 1. 分组
        Map<String, List<LogRow>> logRowMap = logRowList.stream().collect(groupingBy(LogRow::getId));
        // 2. 对每个mapping_id进行统计 成功、失败
        ExecutorService es = ThreadUtil.newExecutor(10);

        logRowMap.forEach((k, v) -> {
            LogRow logRow = v.get(0);
            //统计成功数
            Long count = v.stream().filter(LogRow::isSuccess).count();
            int fail = (v.size() - count.intValue());

            //记录失败数据
            List<SysSyncError> collect = v.stream().filter((r) -> !r.isSuccess()).map(r -> {
                SysSyncError error = new SysSyncError();
                SyncErrorReport syncReport = (SyncErrorReport) r.getSyncReport();
                error.setId(IdUtil.simpleUUID());
                error.setName(r.getMappingName());
                error.setType(r.getErrorType().getCode().toString());
                error.setNameData(r.getNameData());
                error.setNameUpload(r.getNameUpload());
                error.setRowId(StrUtil.utf8Str(syncReport.getDataId()));
                Entity data = syncReport.getData();
                if (data != null) {
                    Map map = data;
                    error.setData(JSONUtil.toJsonStr(map));
                }
                Throwable exception = syncReport.getException();
                if (exception instanceof UndeclaredThrowableException){
                    UndeclaredThrowableException  exception1 = (UndeclaredThrowableException)exception;
                    exception = exception1.getUndeclaredThrowable();
                    if ( exception instanceof InvocationTargetException){
                        InvocationTargetException  exception2 = (InvocationTargetException)exception;
                        exception = exception2.getTargetException();
                    }
                }
                String simpleError = syncReport.getSimpleError();
                if (exception != null){
                    error.setMsg(StrUtil.format("当前错误信息为：{} \n {}",simpleError, ExceptionUtil.stacktraceToString(exception)));
                }
                error.setLock(Switch.OFF.getCode().toString());
                error.setCreateTime(DateUtil.now());

                return error;
            }).collect(Collectors.toList());

            es.execute(()-> calcReport(logRow, count.intValue(), fail));
            es.execute(()-> syncError.saveBatch(collect));

        });


    }


    private void calcReport(LogRow logRow, Integer success, Integer fail) {

        List<TimeEntity> list = TimeEntity.list();
        String nowDate = DateUtil.formatDateTime(new Date());
        for (TimeEntity t : list) {
            SysSyncReport sysSyncReport = findBySysSyncReport(logRow, t);
            sysSyncReport.setSuccess(NumberUtil.add(sysSyncReport.getSuccess(), success.toString()).toString());
            sysSyncReport.setFail(NumberUtil.add(sysSyncReport.getFail(), Integer.toString(fail)).toString());
            sysSyncReport.setUpdateDate(nowDate);
            sysSyncReport.saveOrUpdate();
        }

    }


    private SysSyncReport findBySysSyncReport(LogRow logRow, TimeEntity time) {
        SysSyncReport sysSyncReport = syncReport.queryByMapping(logRow.getMappingId(), logRow.getNameData(), logRow.getNameUpload(), time);
        if (sysSyncReport == null) {
            sysSyncReport = new SysSyncReport();
            sysSyncReport.setMappingId(logRow.getMappingId());
            sysSyncReport.setNameData(logRow.getNameData());
            sysSyncReport.setNameUpload(logRow.getNameUpload());
            sysSyncReport.setSuccess("0");
            sysSyncReport.setFail("0");
            sysSyncReport.setStartDate(time.startDate());
            sysSyncReport.setEndDate(time.endDate());
            sysSyncReport.setCreateDate(DateUtil.formatDateTime(new Date()));
            sysSyncReport.setUpdateDate(DateUtil.formatDateTime(new Date()));
            sysSyncReport.setType(time.getCode());
        }
        return sysSyncReport;
    }


    /**
     * <p>
     * 记录数
     * </p>
     *
     * @Author: Wyndem
     * @DateTime: 2022-12-17 17:54
     */
    public void add(LogRow logRow) {

        logRow.setSuccess(isReportSuccess(logRow.getSyncReport()));
        addRowLog(logRow);
    }


    private void resetList() {
        try {
            lock.lock();
            waitList = new ArrayList<>();
        } finally {
            lock.unlock();
        }
    }


    private void addRowLog(LogRow log) {
        try {
            lock.lock();
            waitList.add(log);
        } finally {
            lock.unlock();
        }

    }


    /**
     * <p>
     * 是否为成功反馈
     * </p>
     *
     * @Author: Wyndem
     * @DateTime: 2022-12-17 17:48
     */
    private boolean isReportSuccess(SyncReport report) {
        if (report instanceof SyncSuccessReport) {
            return true;
        }
        return false;
    }


}
